using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using SumerCoreDevOps.Infrastructure.Identity;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace SumerCoreDevOps.Infrastructure.Identity;

/// <summary>
/// JWT Token 服务
/// 负责生成和验证 JWT Token
/// </summary>
public class JwtTokenService
{
    private readonly ILogger<JwtTokenService> _logger;
    private readonly string _secretKey;
    private readonly string _issuer;
    private readonly string _audience;
    private readonly int _accessTokenExpirationMinutes;
    private readonly int _refreshTokenExpirationDays;
    private readonly TokenBlacklistService? _tokenBlacklistService;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="logger">日志记录器</param>
    /// <param name="secretKey">JWT密钥（至少32字符）</param>
    /// <param name="issuer">发行者</param>
    /// <param name="audience">受众</param>
    /// <param name="accessTokenExpirationMinutes">访问Token过期时间（分钟），默认60分钟</param>
    /// <param name="refreshTokenExpirationDays">刷新Token过期时间（天），默认7天</param>
    public JwtTokenService(
        ILogger<JwtTokenService> logger,
        string secretKey,
        string issuer = "SumerCoreDevOps",
        string audience = "SumerCoreDevOpsClient",
        int accessTokenExpirationMinutes = 60,
        int refreshTokenExpirationDays = 7,
        TokenBlacklistService? tokenBlacklistService = null)
    {
        _logger = logger;

        // 确保密钥长度足够（至少32字符用于HS256）
        if (string.IsNullOrEmpty(secretKey) || secretKey.Length < 32)
        {
            throw new ArgumentException("JWT密钥长度必须至少32字符", nameof(secretKey));
        }

        _secretKey = secretKey;
        _issuer = issuer;
        _audience = audience;
        _accessTokenExpirationMinutes = accessTokenExpirationMinutes;
        _refreshTokenExpirationDays = refreshTokenExpirationDays;
        _tokenBlacklistService = tokenBlacklistService;
    }

    /// <summary>
    /// 生成访问Token
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="username">用户名</param>
    /// <param name="roles">用户角色列表</param>
    /// <param name="permissions">用户权限列表</param>
    /// <returns>JWT Token字符串</returns>
    public string GenerateAccessToken(long userId, string username, List<string> roles, List<string> permissions)
    {
        var claims = new List<Claim>
        {
            new(JwtRegisteredClaimNames.Sub, userId.ToString()),
            new(JwtRegisteredClaimNames.UniqueName, username),
            new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64),
            new("userId", userId.ToString()),
            new("username", username)
        };

        // 添加角色声明
        foreach (var role in roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role));
        }

        // 添加权限声明
        foreach (var permission in permissions)
        {
            claims.Add(new Claim("permission", permission));
        }

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _issuer,
            audience: _audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(_accessTokenExpirationMinutes),
            signingCredentials: credentials
        );

        var tokenString = new JwtSecurityTokenHandler().WriteToken(token);

        _logger.LogDebug("为用户 {Username} (ID: {UserId}) 生成访问Token，过期时间: {Minutes} 分钟",
            username, userId, _accessTokenExpirationMinutes);

        return tokenString;
    }

    /// <summary>
    /// 生成刷新Token
    /// </summary>
    /// <returns>随机生成的刷新Token字符串</returns>
    public string GenerateRefreshToken()
    {
        var randomNumber = new byte[64];
        using var rng = RandomNumberGenerator.Create();
        rng.GetBytes(randomNumber);
        var refreshToken = Convert.ToBase64String(randomNumber);

        _logger.LogDebug("生成刷新Token");

        return refreshToken;
    }

    /// <summary>
    /// 验证Token
    /// </summary>
    /// <param name="token">JWT Token字符串</param>
    /// <returns>验证成功返回ClaimsPrincipal，失败返回null</returns>
    public async Task<ClaimsPrincipal?> ValidateTokenAsync(string token)
    {
        try
        {
            // 检查Token是否在黑名单中
            if (_tokenBlacklistService != null && await _tokenBlacklistService.IsTokenBlacklistedAsync(token))
            {
                _logger.LogWarning("Token验证失败：Token已被撤销");
                return null;
            }

            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.UTF8.GetBytes(_secretKey);

            var validationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = true,
                ValidIssuer = _issuer,
                ValidateAudience = true,
                ValidAudience = _audience,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero // 不允许时钟偏差
            };

            var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);

            if (validatedToken is not JwtSecurityToken jwtToken ||
                !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
            {
                _logger.LogWarning("Token验证失败：签名算法不匹配");
                return null;
            }

            _logger.LogDebug("Token验证成功");
            return principal;
        }
        catch (SecurityTokenExpiredException)
        {
            _logger.LogWarning("Token验证失败：Token已过期");
            return null;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Token验证失败");
            return null;
        }
    }

    /// <summary>
    /// 从Token中提取用户ID（异步版本）
    /// </summary>
    /// <param name="token">JWT Token字符串</param>
    /// <returns>用户ID，失败返回null</returns>
    public async Task<long?> GetUserIdFromTokenAsync(string token)
    {
        var principal = await ValidateTokenAsync(token);
        if (principal == null)
        {
            return null;
        }

        var userIdClaim = principal.FindFirst("userId") ?? principal.FindFirst(JwtRegisteredClaimNames.Sub);
        if (userIdClaim != null && long.TryParse(userIdClaim.Value, out var userId))
        {
            return userId;
        }

        return null;
    }

    /// <summary>
    /// 从Token中提取用户ID（同步版本，允许过期但仍检查黑名单）
    /// </summary>
    /// <param name="token">JWT Token字符串</param>
    /// <returns>用户ID，失败返回null</returns>
    public long? GetUserIdFromToken(string token)
    {
        try
        {
            // 同步检查黑名单
            if (_tokenBlacklistService != null)
            {
                // 注意：这里我们使用Result是因为这是同步方法
                // 在生产环境中，应该考虑重构为完全异步
                if (_tokenBlacklistService.IsTokenBlacklistedAsync(token).Result)
                {
                    _logger.LogWarning("Token已被撤销，无法获取用户ID");
                    return null;
                }
            }

            var tokenHandler = new JwtSecurityTokenHandler();
            if (!tokenHandler.CanReadToken(token))
            {
                return null;
            }

            var jwtToken = tokenHandler.ReadJwtToken(token);
            var userIdClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == "userId" || c.Type == JwtRegisteredClaimNames.Sub);
            
            if (userIdClaim != null && long.TryParse(userIdClaim.Value, out var userId))
            {
                return userId;
            }

            return null;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "从Token提取用户ID失败");
            return null;
        }
    }

    /// <summary>
    /// 从Token中提取用户名
    /// </summary>
    /// <param name="token">JWT Token字符串</param>
    /// <returns>用户名，失败返回null</returns>
    public async Task<string?> GetUsernameFromTokenAsync(string token)
    {
        var principal = await ValidateTokenAsync(token);
        if (principal == null)
        {
            return null;
        }

        var usernameClaim = principal.FindFirst("username") ?? principal.FindFirst(JwtRegisteredClaimNames.UniqueName);
        return usernameClaim?.Value;
    }

    /// <summary>
    /// 获取Token过期时间
    /// </summary>
    public TokenExpirationInfo GetTokenExpiration()
    {
        return new TokenExpirationInfo
        {
            AccessTokenExpirationMinutes = _accessTokenExpirationMinutes,
            RefreshTokenExpirationDays = _refreshTokenExpirationDays
        };
    }
}

/// <summary>
/// Token过期时间信息
/// </summary>
public class TokenExpirationInfo
{
    /// <summary>
    /// 访问Token过期时间（分钟）
    /// </summary>
    public int AccessTokenExpirationMinutes { get; set; }

    /// <summary>
    /// 刷新Token过期时间（天）
    /// </summary>
    public int RefreshTokenExpirationDays { get; set; }
}